#pragma once
#include"IReactor.hpp"
#include"Epoller.hpp"
#include"connection.hpp"


class Reactor:public IReactor{
    const static int defaultfd = -1;

    int IsExistConnection(int fd){
        auto tmpfind = _connection.find(fd);
        if(tmpfind == std::end(_connection))
            return 0;
        return 1;
    }

    void Print(){
        for(auto& item : _connection){
            std::cout<<item.first<<std::endl;
        }
    }

public:
    Reactor():_isrunning(false),_eplptr(std::make_unique<epoller>())
    {
        
    }   

    void Dispatch(int size){
        LOG(level::DEBUG)<<"Dispatching....";
        struct epoll_event* epev = _eplptr->GetStructEvents();
        for(int i = 0;i < size;i++){
            
            int fd = epev[i].data.fd;
            uint32_t events =  epev[i].events;

            if(events & EPOLLERR)
                events |= events |(EPOLLIN | EPOLLOUT);
            if(events & EPOLLHUP)
                events |= events | (EPOLLIN | EPOLLOUT);     

            if(events & (EPOLLIN)){
                _connection[fd]->Recv();
            }
            if(events & (EPOLLOUT)){
                _connection[fd]->Send();
            }

        }
    }

    void LoopOne(int timeout){
         int ret = _eplptr->Wait(timeout);
            switch (ret)
            {
            case -1:
                LOG(level::WARING)<<"select fail";
                break;
            case 0:
                LOG(level::DEBUG)<<"timeout..";
                break;
            default:
                Dispatch(ret);
            }
    }

    void start(){
        _isrunning = true;
        while(_isrunning)
        {
            int timeout = -1;
           LoopOne(timeout);
        }
        _isrunning = false;
    }

    void Stop()
    {
        _isrunning = false;
    }

    void Delconnection(int fd){
        uint32_t events = 0;
        _eplptr->Delect(fd,events);
        _connection.erase(fd);
        close(fd);
    }

    void OpenReadAndWrite(int sockfd,bool enread,bool enwrite){
        if(!IsExistConnection(sockfd)){
            LOG(level::WARING)<<"sockfd no exist";
            return;
        }

        uint32_t new_events = (EPOLLET | (enread?EPOLLIN:0) | (enwrite?EPOLLOUT:0));
        _connection[sockfd]->Setevents(new_events);
        _eplptr->Mod(sockfd,new_events);
        
    }

    void Addconnection(std::shared_ptr<connection> con){
        if(IsExistConnection(con->Getfd())){
            LOG(level::WARING)<<"addconnection false";
            return;
        }
        _eplptr->Add(con->Getfd(),con->Getevents());
        con->SetReactor(this);
        _connection[con->Getfd()] = con;
    }

    ~Reactor(){}

private:

    std::unique_ptr<epoller> _eplptr;
    std::unordered_map<int,std::shared_ptr<connection>> _connection;

    bool _isrunning;
};